#pragma once
#include <iostream>
#include <queue>
#include <vector>
#include <pthread.h>
#include <time.h>
#include "log.hpp"

const int defaultnum = 3;

template <typename T>
class ThreadPool
{
public:
    ~ThreadPool()
    {
        pthread_mutex_destroy(&lock);
        pthread_cond_destroy(&cond);
    }

    void init()
    {
        running = true;
        for (int i = 0; i < threadnum; i++)
        {
            pthread_t id;
            pthread_create(&id, nullptr, start, this);
        }
    }

    void waitAll()
    {
        for (auto thread : threads)
        {
            pthread_join(thread, nullptr);
        }
    }

    void push(T t)
    {
        lockQue();
        if (running)
        {
            que.push(t);
        }
        unlockQue();
        wake();
    }

    void pop(T *t)
    {
        if (que.empty())
            return;
        *t = que.front();
        que.pop();
    }

    // 停止线程池
    void stop()
    {
        lockQue();
        running = false;
        waitAll();
        unlockQue();
    }

    static ThreadPool<T> *GetInstance()
    {
        if (nullptr == inst)//减少获取单例的加锁成本
        {
            pthread_mutex_lock(&lock);//如果每个线程都要获取一遍锁效率就太低了
            if (nullptr == inst)
            {
                Log(DEBUG, "构建线程池单例");
                inst = new ThreadPool<T>();
                inst->init();
                start(inst);
                return inst;
            }
            pthread_mutex_unlock(&lock);
        }
        //日志打印是线程安全的
        Log(DEBUG, "获取线程池单例");
        return inst;
    }

private:
    int threadnum;
    bool running;
    std::queue<T> que;
    std::vector<pthread_t> threads;
    pthread_mutex_t lock;
    pthread_cond_t cond;
    int waitnum; // 有多少个线程正在等待
    // 添加单例模式
    static ThreadPool<T> *inst;
    static pthread_mutex_t lock;

    ThreadPool(int num = defaultnum)
        : threadnum(num), running(false), waitnum(num)
    {
        Log(INFO, "threadpool create");
        pthread_mutex_init(&lock, nullptr);
        pthread_cond_init(&cond, nullptr);
    }

    // 单例模式将拷贝构造和赋值函数禁掉
    ThreadPool<T> &operator=(const ThreadPool<T> &t) = delete;
    ThreadPool(const ThreadPool<T> &t) = delete;

    static void *start(void *argc)
    {
        ThreadPool<T> *tp = (ThreadPool *)argc;
        while (true)
        {
            tp->lockQue();
            // 线程池还在工作 && 队列中没有任务
            while (tp->running && !tp->que.empty())
            {
                tp->wait();
            }
            // 线程池已经退出 && 任务队列为空
            if (!tp->running && tp->que.empty())
            {
                tp->unlockQue();
                break;
            }
            // 线程池还在工作 && 任务队列中有任务
            // 线程池已经退出 && 任务队列中还有任务
            srand(time(nullptr));
            T task(rand() % 3, rand() % 7);
            tp->pop(&task);
            tp->unlockQue();

            // 处理任务
            task();
        }
        return nullptr;
    }

    void lockQue()
    {
        pthread_mutex_lock(&lock);
    }
    void unlockQue()
    {
        pthread_mutex_unlock(&lock);
    }
    void wake()
    {
        pthread_cond_signal(&cond);
    }
    void wakeAll()
    {
        pthread_cond_broadcast(&cond);
    }
    void wait()
    {
        pthread_cond_wait(&cond, &lock);
    }
};

template <typename T>
ThreadPool<T> *ThreadPool<T>::inst = nullptr;

template <typename T>
pthread_mutex_t ThreadPool<T>::lock = PTHRUTEX_INITIALIZER;